"""
@author: 江同学呀
@file: intervals_rule.py
@date: 2025/1/13 20:49
@desc: 
"""
from typing import Union, Dict, Iterable

from espc.orm.model.base.base import _Base
from espc.orm.model.mapping.field.base_field.base_field import _BaseField
from espc.orm.model.scripting.script import Script
from espc.orm.model.text_analysis.analyzer import BaseAnalyzer


class IntervalsRule(_Base):
    """
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-intervals-query.html#intervals-top-level-params
    """
    type: str


class FilterRule(IntervalsRule):
    """
    筛选规则参数

    The filter rule returns intervals based on a query. See Filter example for an example.
    筛选规则根据查询返回间隔。有关示例，请参阅 Filter example 。

    :param after:
        (Optional, query object) Query used to return intervals that follow an interval from the filter rule.
        （可选，查询对象）Query 用于返回筛选规则中间隔之后的间隔。
    :param before:
        (Optional, query object) Query used to return intervals that occur before an interval from the filter rule.
        （可选，查询对象）Query 用于从筛选规则中返回在间隔之前发生的间隔。
    :param contained_by:
        (Optional, query object) Query used to return intervals contained by an interval from the filter rule.
        （可选，查询对象）Query 用于从筛选规则中返回间隔所包含的间隔。
    :param containing:
        (Optional, query object) Query used to return intervals that contain an interval from the filter rule.
        （可选，查询对象）Query 用于返回包含筛选规则中的间隔的间隔。
    :param not_contained_by:
        (Optional, query object) Query used to return intervals that are not contained by an interval from the filter
        rule.
        （可选，查询对象）Query 用于返回筛选规则中间隔不包含的间隔。
    :param not_containing:
        (Optional, query object) Query used to return intervals that do not contain an interval from the filter rule.
        （可选，查询对象）Query 用于返回不包含筛选规则中间隔的间隔。
    :param not_overlapping:
        (Optional, query object) Query used to return intervals that do not overlap with an interval from the filter
        rule.
        （可选，查询对象）Query 用于返回与筛选规则中的间隔不重叠的间隔。
    :param overlapping:
        (Optional, query object) Query used to return intervals that overlap with an interval from the filter rule.
        （可选，查询对象）Query 用于返回与筛选规则中的间隔重叠的间隔。
    :param script:
        (Optional, script object) Script used to return matching documents. This script must return a boolean value,
        true or false. See Script filters for an example.
        （可选，script 对象）用于返回匹配文档的脚本。此脚本必须返回布尔值 true 或 false。有关示例，请参阅 脚本过滤器 。
    """

    def __init__(
            self, after: Union[Dict, IntervalsRule] = None, before: Union[Dict, IntervalsRule] = None,
            contained_by: Union[Dict, IntervalsRule] = None, containing: Union[Dict, IntervalsRule] = None,
            not_contained_by: Union[Dict, IntervalsRule] = None, not_containing: Union[Dict, IntervalsRule] = None,
            not_overlapping: Union[Dict, IntervalsRule] = None, overlapping: Union[Dict, IntervalsRule] = None,
            script: Union[Dict, Script] = None):
        super().__init__()
        self._after: Union[Dict, IntervalsRule] = after
        self._before: Union[Dict, IntervalsRule] = before
        self._contained_by: Union[Dict, IntervalsRule] = contained_by
        self._containing: Union[Dict, IntervalsRule] = containing
        self._not_contained_by: Union[Dict, IntervalsRule] = not_contained_by
        self._not_containing: Union[Dict, IntervalsRule] = not_containing
        self._not_overlapping: Union[Dict, IntervalsRule] = not_overlapping
        self._overlapping: Union[Dict, IntervalsRule] = overlapping
        self._script: Union[Dict, Script] = script
        return

    def _build(self) -> Dict:
        _body: Dict = {}
        if self._after:
            _body["after"] = self._after if isinstance(self._after, Dict) else self._after._build()
        if self._before:
            _body["before"] = self._before if isinstance(self._before, Dict) else self._before._build()
        if self._contained_by:
            _body["contained_by"] = (
                self._contained_by if isinstance(self._contained_by, Dict) else self._contained_by._build()
            )
        if self._containing:
            _body["containing"] = (
                self._containing if isinstance(self._containing, Dict) else self._containing._build()
            )
        if self._not_contained_by:
            _body["not_contained_by"] = (
                self._not_contained_by if isinstance(self._not_contained_by, Dict) else self._not_contained_by._build()
            )
        if self._not_containing:
            _body["not_containing"] = (
                self._not_containing if isinstance(self._not_containing, Dict) else self._not_containing._build()
            )
        if self._not_overlapping:
            _body["not_overlapping"] = (
                self._not_overlapping if isinstance(self._not_overlapping, Dict) else self._not_overlapping._build()
            )
        if self._overlapping:
            _body["overlapping"] = (
                self._overlapping if isinstance(self._overlapping, Dict) else self._overlapping._build()
            )
        if self._script:
            _body["script"] = self._script if isinstance(self._script, Dict) else self._script._build()
        return _body


class MatchRule(IntervalsRule):
    """
    前缀规则参数

    The match rule matches analyzed text.
    匹配规则匹配已分析的文本。

    :param query:
        (Required, string) Text you wish to find in the provided <field>.
        （必需，字符串）您希望在提供的 <field> 中找到的文本。
    :param max_gaps:
        (Optional, integer) Maximum number of positions between the matching terms. Terms further apart than this are
        not considered matches. Defaults to -1.
        If unspecified or set to -1, there is no width restriction on the match. If set to 0, the terms must appear next
        to each other.

        （可选，整数）匹配词之间的最大位置数。相差较远的术语不被视为匹配项。默认为 -1。
        如果未指定或设置为 -1，则对匹配项没有宽度限制。如果设置为 0，则术语必须彼此相邻显示。
    :param ordered:
        (Optional, Boolean) If true, matching terms must appear in their specified order. Defaults to false.
        （可选，布尔值）如果为 true，则匹配词必须按其指定顺序显示。默认为 false。
    :param analyzer:
        (Optional, string) analyzer used to analyze terms in the query. Defaults to the top-level <field>'s analyzer.
        （可选，字符串）analyzer 用于分析查询中的术语。默认为顶级 <field> 的分析器。
    :param filter_:
        (Optional, interval filter rule object) An optional interval filter.
        （可选，间隔筛选规则对象）可选的间隔筛选器。
    :param use_field:
        (Optional, string) If specified, then match intervals from this field rather than the top-level <field>. Terms
        are analyzed using the search analyzer from this field. This allows you to search across multiple fields as if
        they were all the same field; for example, you could index the same text into stemmed and unstemmed fields, and
        search for stemmed tokens near unstemmed ones.
        （可选，字符串）如果指定，则匹配此字段的间隔，而不是顶级 <field>。使用此字段中的搜索分析器分析术语。这允许您跨多个字段进行搜索，就好像
        它们都是同一个字段一样;例如，您可以将同一文本索引到词干和无词干字段中，并在无词干标记附近搜索词干标记。
    """
    type: str = "match"

    def __init__(
            self, query: str, max_gaps: int = None, ordered: bool = None, analyzer: Union[str, BaseAnalyzer] = None,
            filter_: Union[Dict, FilterRule] = None, use_field: Union[str, _BaseField] = None
    ):
        super().__init__()
        self._query: str = query
        self._max_gaps: int = max_gaps
        self._ordered: bool = ordered
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._filter: Union[Dict, FilterRule] = filter_
        self._use_field: Union[str, _BaseField] = use_field
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "query": self._query,
        }
        if self._max_gaps is not None:
            _body["max_gaps"] = self._max_gaps
        if self._ordered is not None:
            _body["ordered"] = self._ordered
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._filter:
            _body["filter"] = self._filter if isinstance(self._filter, Dict) else self._filter._build()
        if self._use_field:
            _body["use_field"] = self._use_field
        return _body


class PrefixRule(IntervalsRule):
    """
    前缀规则参数

    The prefix rule matches terms that start with a specified set of characters. This prefix can expand to match at
    most 128 terms. If the prefix matches more than 128 terms, Elasticsearch returns an error. You can use the
    index-prefixes option in the field mapping to avoid this limit.
    前缀规则匹配以一组指定字符开头的术语。此前缀可以扩展为最多匹配 128 个字词。如果前缀匹配的字词超过 128 个，Elasticsearch 将返回错误。
    您可以在字段映射中使用 index-prefixes 选项来避免此限制。

    :param prefix:
        (Required, string) Beginning characters of terms you wish to find in the top-level <field>.
        （必需，字符串）您希望在顶级 <field> 中找到的术语的开始字符。
    :param analyzer:
        (Optional, string) analyzer used to normalize the prefix. Defaults to the top-level <field>'s analyzer.
        （可选，字符串）analyzer 用于规范化前缀。默认为顶级 <field> 的分析器。
    :param use_field:
        (Optional, string) If specified, then match intervals from this field rather than the top-level <field>.
        The prefix is normalized using the search analyzer from this field, unless a separate analyzer is specified.

        （可选，字符串）如果指定，则匹配此字段的间隔，而不是顶级 <field>。
        前缀使用此字段中的搜索分析器进行规范化，除非指定了单独的分析器。
    """
    type: str = "prefix"

    def __init__(
            self, prefix: str, analyzer: Union[str, BaseAnalyzer] = None,
            use_field: Union[str, _BaseField] = None
    ):
        super().__init__()
        self._prefix: str = prefix
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._use_field: Union[str, _BaseField] = use_field
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "prefix": self._prefix,
        }
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._use_field:
            _body["use_field"] = self._use_field if isinstance(self._use_field, str) else self._use_field._field_name
        return _body


class WildcardRule(IntervalsRule):
    """
    通配符规则参数

    The wildcard rule matches terms using a wildcard pattern. This pattern can expand to match at most 128 terms. If
    the pattern matches more than 128 terms, Elasticsearch returns an error.
    通配符规则使用通配符模式匹配术语。此模式最多可以扩展以匹配 128 个字词。如果模式匹配的字词超过 128 个，Elasticsearch 将返回错误。

    :param pattern:
        (Required, string) Wildcard pattern used to find matching terms.
        This parameter supports two wildcard operators:
            - ?, which matches any single character
            - *, which can match zero or more characters, including an empty one
        Avoid beginning patterns with * or ?. This can increase the iterations needed to find matching terms and slow
        search performance.

        （必需，字符串）用于查找匹配词的通配符模式。
        此参数支持两种通配符运算符：
            - ？，它匹配任何单个字符
            - *，它可以匹配零个或多个字符，包括一个空字符
        避免以 * 或 ？开头。这可能会增加查找匹配词所需的迭代次数，并降低搜索性能。
    :param analyzer:
        (Optional, string) analyzer used to normalize the pattern. Defaults to the top-level <field>'s analyzer.
        （可选，字符串）analyzer 用于规范化模式。默认为顶级 <field> 的分析器。
    :param use_field:
        (Optional, string) If specified, match intervals from this field rather than the top-level <field>.
        The pattern is normalized using the search analyzer from this field, unless analyzer is specified separately.

        （可选，字符串）如果指定，则匹配此字段的间隔，而不是顶级 <field>。
        除非单独指定了 analyzer，否则使用此字段中的搜索分析器对模式进行规范化。
    """
    type: str = "wildcard"

    def __init__(
            self, pattern: str, analyzer: Union[str, BaseAnalyzer] = None,
            use_field: Union[str, _BaseField] = None
    ):
        super().__init__()
        self._pattern: str = pattern
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._use_field: Union[str, _BaseField] = use_field
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "pattern": self._pattern,
        }
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._use_field:
            _body["use_field"] = self._use_field if isinstance(self._use_field, str) else self._use_field._field_name
        return _body


class FuzzyRule(IntervalsRule):
    """
    模糊规则参数

    The fuzzy rule matches terms that are similar to the provided term, within an edit distance defined by Fuzziness.
    If the fuzzy expansion matches more than 128 terms, Elasticsearch returns an error.
    模糊规则匹配与提供的术语相似的术语，在模糊度定义的编辑距离内。如果模糊扩展匹配超过 128 个术语，Elasticsearch 将返回错误。

    :param term:
        (Required, string) The term to match
        （必需，字符串）要匹配的术语
    :param prefix_length:
        (Optional, integer) Number of beginning characters left unchanged when creating expansions. Defaults to 0.
        （可选，整数）创建扩展时保持不变的开始字符数。默认为 0。
    :param transpositions:
        (Optional, Boolean) Indicates whether edits include transpositions of two adjacent characters (ab → ba).
        Defaults to true.
        （可选，布尔值）指示编辑是否包括两个相邻字符 （ab → ba） 的移调。默认为 true。
    :param fuzziness:
        (Optional, string) Maximum edit distance allowed for matching. See Fuzziness for valid values and more
        information. Defaults to auto.
        （可选，字符串）允许匹配的最大编辑距离。请参阅 Fuzziness 了解有效值和更多信息。默认为 auto。
    :param analyzer:
        (Optional, string) analyzer used to normalize the term. Defaults to the top-level <field> 's analyzer.
        （可选，字符串）analyzer 用于规范化术语。默认为顶级 <field> 的分析器。
    :param use_field:
        (Optional, string) If specified, match intervals from this field rather than the top-level <field>.
        The term is normalized using the search analyzer from this field, unless analyzer is specified separately.

        （可选，字符串）如果指定，则匹配此字段的间隔，而不是顶级 <field>。
        除非单独指定了 analyzer，否则使用此字段中的搜索分析器对术语进行规范化。
    """
    type: str = "fuzzy"

    def __init__(
            self, term: str, prefix_length: int = None, transpositions: bool = None, fuzziness: str = None,
            analyzer: Union[str, BaseAnalyzer] = None, use_field: Union[str, _BaseField] = None
    ):
        super().__init__()
        self._term: str = term
        self._prefix_length: int = prefix_length
        self._transpositions: bool = transpositions
        self._fuzziness: str = fuzziness
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._use_field: Union[str, _BaseField] = use_field
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "term": self._term,
        }
        if self._prefix_length is not None:
            _body["prefix_length"] = self._prefix_length
        if self._transpositions is not None:
            _body["transpositions"] = self._transpositions
        if self._fuzziness:
            _body["fuzziness"] = self._fuzziness
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._use_field:
            _body["use_field"] = self._use_field if isinstance(self._use_field, str) else self._use_field._field_name
        return _body


class AllOfRule(IntervalsRule):
    """
    all_of 规则参数

    The all_of rule returns matches that span a combination of other rules.
    all_of 规则返回跨其他规则组合的匹配项。

    :param intervals:
        (Required, array of rule objects) An array of rules to combine. All rules must produce a match in a document
        for the overall source to match.
        （必需，规则对象数组）要组合的规则数组。所有规则都必须在文档中生成匹配项，才能使整个源匹配。
    :param max_gaps:
        (Optional, integer) Maximum number of positions between the matching terms. Intervals produced by the rules
        further apart than this are not considered matches. Defaults to -1.
        If unspecified or set to -1, there is no width restriction on the match. If set to 0, the terms must appear
        next to each other.

        （可选，整数）匹配词之间的最大位置数。由相距较远的规则产生的间隔不被视为匹配项。默认为 -1。
        如果未指定或设置为 -1，则对匹配项没有宽度限制。如果设置为 0，则术语必须彼此相邻显示。
    :param ordered:
        (Optional, Boolean) If true, intervals produced by the rules should appear in the order in which they are
        specified. Defaults to false.
        （可选，布尔值）如果为 true，则规则生成的间隔应按指定的顺序显示。默认为 false。
    :param filter_:
        (Optional, interval filter rule object) Rule used to filter returned intervals.
        （可选，间隔筛选规则对象）用于筛选返回的间隔的规则。
    """
    type: str = "all_of"

    def __init__(
            self, intervals: Iterable[IntervalsRule], max_gaps: int = None, ordered: bool = None,
            filter_: Union[Dict, FilterRule] = None
    ):
        super().__init__()
        self._intervals: Iterable[IntervalsRule] = intervals
        self._max_gaps: int = max_gaps
        self._ordered: bool = ordered
        self._filter: Union[Dict, FilterRule] = filter_
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "intervals": [
                {
                    interval.type: interval._build()
                }
                for interval in self._intervals
            ]
        }
        if self._max_gaps is not None:
            _body["max_gaps"] = self._max_gaps
        if self._ordered is not None:
            _body["ordered"] = self._ordered
        if self._filter:
            _body["filter"] = self._filter if isinstance(self._filter, Dict) else self._filter._build()
        return _body


class AnyOfRule(IntervalsRule):
    """
    any_of规则参数

    The any_of rule returns intervals produced by any of its sub-rules.
    any_of 规则返回其任何子规则生成的间隔。

    :param intervals:
        (Required, array of rule objects) An array of rules to match.
        （必需，规则对象数组）要匹配的规则数组。
    :param filter_:
        (Optional, interval filter rule object) Rule used to filter returned intervals.
        （可选，间隔筛选规则对象）用于筛选返回的间隔的规则。
    """
    type: str = "any_of"

    def __init__(
            self, intervals: Iterable[IntervalsRule], filter_: Union[Dict, FilterRule] = None
    ):
        super().__init__()
        self._intervals: Iterable[IntervalsRule] = intervals
        self._filter: Union[Dict, FilterRule] = filter_
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "intervals": [
                {
                    interval.type: interval._build()
                }
                for interval in self._intervals
            ]
        }
        if self._filter:
            _body["filter"] = self._filter if isinstance(self._filter, Dict) else self._filter._build()
        return _body
